﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices;
using System.Web;
using System.Collections;

namespace ADAuthentication.Framework
{
    public static class ActiveDirectoryHelper
    {
        #region Properties

        #endregion

        #region Authenticateion

        public static bool IsAutheticated(string path, string domain, string username, string password)
        {
            string domainUserName = domain + "\\" + username;
            DirectoryEntry directoryEntry = new DirectoryEntry(path, domainUserName, password);
            try
            {
                object nativeObject = directoryEntry.NativeObject;

                DirectorySearcher searcher = new DirectorySearcher(directoryEntry);

                searcher.Filter = String.Format("(SAMAccountName={0})", username).ToString();
                searcher.PropertiesToLoad.Add("cn");
                SearchResult result = searcher.FindOne();

                if (null != result)
                {
                    return true;
                }
            }
            catch (Exception e)
            {
            }
            return false;
        }

        #endregion

        #region User and User Group

        public static List<string> GetGroupNames(string path)
        {
            List<string> allGroups = new List<string>();

            List<DirectoryEntry> allGroupEntries = GetGroupEntries(path);
            foreach (var entry in allGroupEntries)
            {
                object groupName = GetPropertyValue(entry, "samaccountname", 0);
                if (null != groupName)
                {
                    allGroups.Add(groupName.ToString());
                }
            }

            return allGroups;
        }

        public static List<DirectoryEntry> GetGroupEntries(string path)
        {
            List<DirectoryEntry> allGroups = new List<DirectoryEntry>();

            DirectoryEntry directoryEntry = new DirectoryEntry(path);

            try
            {
                DirectorySearcher searcher = new DirectorySearcher(directoryEntry, "(objectCategory=group)");
                SearchResultCollection resultCollection = searcher.FindAll();
                for (int i = 0; i < resultCollection.Count; i++)
                {
                    DirectoryEntry entry = resultCollection[i].GetDirectoryEntry();

                    allGroups.Add(entry);                     
                }
            }
            catch (Exception e)
            {
            }

            return allGroups;
        }

        public static DirectoryEntry GetGroup(string path, string groupName)
        {
            return GetGroup(new DirectoryEntry(path), groupName);
        }

        public static DirectoryEntry GetGroup(DirectoryEntry entry, string groupName)
        {
            try
            {
                DirectorySearcher groupSearcher = new DirectorySearcher(entry, String.Format("(&(objectCategory=group)(sAMAccountName={0}))", groupName).ToString());
                var result = groupSearcher.FindOne();
                if (null != result)
                {
                    return result.GetDirectoryEntry();
                }
            }
            catch (Exception e)
            {
            }
            return null;
        }

        public static List<DirectoryEntry> GetUsers(string path)
        {
            List<DirectoryEntry> allEntries = new List<DirectoryEntry>();

            DirectoryEntry directoryEntry = new DirectoryEntry(path);

            try
            {
                DirectorySearcher searcher = new DirectorySearcher(directoryEntry, "(objectCategory=user)");
                SearchResultCollection resultCollection = searcher.FindAll();
                for (int i = 0; i < resultCollection.Count; i++)
                {
                    allEntries.Add(resultCollection[i].GetDirectoryEntry());
                }
            }
            catch (Exception e)
            {
            }

            return allEntries;
        }

        /// <summary>
        /// Get the users in special group
        /// </summary>
        /// <param name="path">search directory entry path</param>
        /// <param name="groupName">group name with the format: groupname</param>
        /// <param name="propertiesToLoad"></param>
        /// <returns></returns>
        public static List<DirectoryEntry> GetUsers(string path, string groupName)
        {
            List<DirectoryEntry> allEntries = new List<DirectoryEntry>();

            DirectoryEntry directoryEntry = new DirectoryEntry(path);

            try
            {
                DirectoryEntry groupEntry = GetGroup(directoryEntry, groupName);

                DirectorySearcher searcher = new DirectorySearcher(directoryEntry);

                searcher.Filter = "(objectCategory=user)";
                searcher.PropertiesToLoad.Add("memberOf");

                SearchResultCollection resultCollection = searcher.FindAll();
                for (int i = 0; i < resultCollection.Count; i++)
                {
                    var memberEntry = resultCollection[i].GetDirectoryEntry();
                    var groupProperties = resultCollection[i].Properties["memberOf"];
                    if (groupProperties != null)
                    {
                        for (int j = 0; j < groupProperties.Count; j++)
                        {
                            if (groupProperties[j] != null && "LDAP://" + groupProperties[j].ToString() == groupEntry.Path)
                            {
                                allEntries.Add(resultCollection[i].GetDirectoryEntry());
                                break;
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
            }

            return allEntries;
        }

        #endregion

        #region Sync Data from AD to Users

        public static int SynchronizeADInfoToUsers(string path)
        {
            int count = 0;

            List<DirectoryEntry> allUserEntries = GetUsers(path);

            foreach (var userEntry in allUserEntries)
            {
                try
                {
                    User user = new User();
                    user.FirstName = (GetPropertyValue(userEntry, "givenname", 0) ?? String.Empty).ToString();
                    user.LastName = (GetPropertyValue(userEntry, "sn", 0) ?? String.Empty).ToString();
                    user.Email = (GetPropertyValue(userEntry, "mail", 0) ?? String.Empty).ToString();
                    user.UserName = (GetPropertyValue(userEntry, "samaccountname", 0) ?? String.Empty).ToString();
                    user.IsActive = Convert.ToBoolean(GetPropertyValue(userEntry, "msrtcsip-userenabled", 0) ?? "False");
                    user.Password = string.Empty;
                    user.IsSuperUser = false;
                    user.LastModified = Convert.ToDateTime(GetPropertyValue(userEntry, "whenchanged", 0) ?? DateTime.MinValue);
                     
                }
                catch (Exception e)
                {
                }
            }

            return count;
        }

        #endregion

        #region Sync Data From AD to Member Group and Member

        public static int SynchronizeADInfoToMembers(string path)
        {
            int count = 0;
            return count;
        }

        public static int SynchronizeADInfoToMembers(string path, string adGroup)
        {
            int count = 0;
            return count;
        }

        #endregion

        #region Assist Methods

        public static object[] GetPropertyValues(DirectoryEntry entry, string propertyName)
        {            
            if (entry != null)
            {
                var allPropertyValues = new List<object>();
                var propertyValueCollection = entry.Properties[propertyName];
                if (propertyValueCollection != null)
                {
                    for (int i = 0; i < propertyValueCollection.Count; i++)
                    {
                        allPropertyValues.Add(propertyValueCollection[i]);
                    }
                }
                return allPropertyValues.ToArray();
            }
            return new object[0];
        }

        public static object GetPropertyValue(DirectoryEntry entry, string propertyName, int index)
        {
            object[] allPropertyValues = GetPropertyValues(entry, propertyName);
            if (allPropertyValues != null && allPropertyValues.Length > 0 && allPropertyValues.Length > index)
            {
                return allPropertyValues[index];
            }
            return null;
        }

        #endregion
    }

    public class User
    {
        public string FirstName { get; set; }

        public string LastName { get; set; }

        public string Email { get; set; }

        public string UserName { get; set; }

        public bool IsActive { get; set; }

        public string Password { get; set; }

        public bool IsSuperUser { get; set; }

        public DateTime LastModified { get; set; }
    }
}
